home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 11 / CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso / cucd / programming / oberonv4 / source / system / keplergraphs.mod (.txt) < prev    next >
Oberon Text  |  1995-06-12  |  17KB  |  545 lines

  1. Syntax10.Scn.Fnt
  2. MODULE KeplerGraphs;    (* J. Templ, 30.10.90 *)
  3.     IMPORT SYSTEM, KeplerPorts, Display, Files, Oberon, Modules, Types, Texts;
  4.     CONST
  5.         draw* = 0; restore* = 1;    (* notify op-codes *)
  6.         ptSize = 12;
  7.         maxNofpts = 4;
  8.     (* graph = {star} {configuration} 0X.
  9.         star = header contents.
  10.         configuration = header contents.
  11.         header = typeref [typename].
  12.         typeref = compact-integer.
  13.         typename = qualident 0X.
  14.         contents = {byte}. *)
  15.     TYPE
  16.         Object* = POINTER TO ObjectDesc;
  17.         ObjectDesc* = RECORD END ;
  18.         Star* = POINTER TO StarDesc;
  19.         StarDesc* = RECORD
  20.             (ObjectDesc)
  21.             x*, y*, refcnt*, ref: INTEGER;
  22.             sel*: BOOLEAN;
  23.             next* : Star;
  24.         END ;
  25.         Constellation* = POINTER TO ConsDesc;
  26.         ConsDesc* = RECORD
  27.             (ObjectDesc)
  28.             nofpts*: INTEGER;
  29.             p*: ARRAY maxNofpts OF Star;
  30.             next*: Constellation;
  31.         END ;
  32.         Planet* = POINTER TO PlanetDesc;
  33.         PlanetDesc* = RECORD
  34.             (StarDesc)
  35.             c*: Constellation;
  36.         END;
  37.         Graph* = POINTER TO GraphDesc;
  38.         Notifier* = PROCEDURE (op: INTEGER; G: Graph; O: Object; P: KeplerPorts.Port);
  39.         GraphDesc* = RECORD
  40.             (ObjectDesc)
  41.             cons*, lastcons: Constellation;
  42.             stars*, laststar: Star;
  43.             seltime*: LONGINT;
  44.             notify*: Notifier;
  45.         END ;
  46.         StarTab = POINTER TO ARRAY OF LONGINT;
  47.         loading*: Graph;
  48.         update: KeplerPorts.BalloonPort;
  49.         nofpt: INTEGER;
  50.         starTab: StarTab;
  51.         noftypes: LONGINT;
  52.         typTab: ARRAY 256 OF LONGINT;
  53.         del, delG: Graph;
  54.     (* ---------------------------------- abstract methods ---------------------------------- *)
  55.     PROCEDURE (self: Object) Draw* (P: KeplerPorts.Port);
  56.     END Draw;
  57.     PROCEDURE (self: Object) Read* (VAR R: Files.Rider);
  58.     END Read;
  59.     PROCEDURE (self: Object) Write* (VAR R: Files.Rider);
  60.     END Write;
  61.     (* ---------------------------------- auxiliary procedures ---------------------------------- *)
  62.     PROCEDURE err(s0, s1: ARRAY OF CHAR);
  63.         VAR W: Texts.Writer;
  64.     BEGIN Texts.OpenWriter(W);
  65.         Texts.WriteString(W, s0); Texts.WriteString(W, s1); Texts.WriteLn(W);
  66.         Texts.Append(Oberon.Log, W.buf)
  67.     END err;
  68.     PROCEDURE err2(s0, s1: ARRAY OF CHAR);
  69.         VAR W: Texts.Writer;
  70.     BEGIN Texts.OpenWriter(W);
  71.         Texts.WriteString(W, s0); Texts.WriteString(W, s1);
  72.         Texts.Append(Oberon.Log, W.buf)
  73.     END err2;
  74.     PROCEDURE ReadObj* (VAR R: Files.Rider; VAR x: Object);
  75.         VAR ref: LONGINT;
  76.             m: Modules.Module; t: Types.Type;
  77.             module, type: ARRAY 32 OF CHAR;
  78.     BEGIN x := NIL;
  79.         Files.ReadNum(R, ref);
  80.         IF ref = noftypes THEN
  81.             Files.ReadString(R, module);
  82.             Files.ReadString(R, type);
  83.             m := Modules.ThisMod(module);
  84.             IF m # NIL THEN t := Types.This(m, type);
  85.                 IF t # NIL THEN typTab[ref] := SYSTEM.VAL(LONGINT, t); INC(noftypes);
  86.                     Types.NewObj(x, t); x.Read(R)
  87.                 ELSE err("-- type not found: ", type)
  88.                 END
  89.             ELSE err2("-- error: ", Modules.importing);
  90.                 IF Modules.res = 2 THEN err(" not an obj-file", "")
  91.                 ELSIF Modules.res = 3 THEN err2(" imports ", Modules.imported); err(" with bad key", "");
  92.                 ELSIF Modules.res = 4 THEN err(" corrupted obj file", "")
  93.                 ELSIF Modules.res = 7 THEN err(" not enough space", "")
  94.                 END;
  95.                 (*Modules.res := 0*)
  96.             END
  97.         ELSIF ref # -1 THEN
  98.             Types.NewObj(x, SYSTEM.VAL(Types.Type, typTab[ref]));
  99.             x.Read(R)
  100.         END
  101.     END ReadObj;
  102.     PROCEDURE WriteObj* (VAR R: Files.Rider; x: Object);
  103.         VAR typ: Types.Type; i: LONGINT;
  104.     BEGIN
  105.         IF x # NIL THEN
  106.             typ := Types.TypeOf(x); i := 0;
  107.             WHILE (i < noftypes) & (SYSTEM.VAL(LONGINT, typ) # typTab[i]) DO INC(i) END ;
  108.             IF i = noftypes THEN
  109.                 Files.WriteNum(R, i);
  110.                 typTab[i] := SYSTEM.VAL(LONGINT, typ); INC(noftypes);
  111.                 Files.WriteString(R, typ.module.name);
  112.                 Files.WriteString(R, typ.name)
  113.             ELSE
  114.                 Files.WriteNum(R, i)
  115.             END ;
  116.             x.Write(R)
  117.         ELSE Files.WriteNum(R, -1)
  118.         END
  119.     END WriteObj;
  120.     PROCEDURE GetType* (o: Object; VAR module, type: ARRAY OF CHAR);
  121.         VAR t: Types.Type;
  122.     BEGIN t := Types.TypeOf(o); COPY(t.module.name, module); COPY(t.name, type)
  123.     END GetType;
  124.     PROCEDURE Reset*;
  125.     BEGIN nofpt := 0; noftypes := 0
  126.     END Reset;
  127.     PROCEDURE GetStar (n: INTEGER): Star;
  128.         VAR s: Star;
  129.     BEGIN s := SYSTEM.VAL(Star, starTab[n]); INC(s.refcnt); RETURN s
  130.     END GetStar;
  131.     (* ---------------------------------- Star methods ---------------------------------- *)
  132.     PROCEDURE (self: Star) Draw* (P: KeplerPorts.Port);
  133.     BEGIN
  134.         IF self.sel THEN
  135.             P.FillRect(self.x - ptSize, self.y - ptSize, ptSize*2 + P.scale, ptSize*2 + P.scale, Display.white, 5, Display.invert)
  136.         END
  137.     END Draw;
  138.     PROCEDURE (self: Star) Read* (VAR R: Files.Rider);
  139.         VAR h: LONGINT;
  140.     BEGIN self.sel := FALSE;
  141.         Files.ReadNum(R, h); self.x := SHORT(h);
  142.         Files.ReadNum(R, h); self.y := SHORT(h)
  143.     END Read;
  144.     PROCEDURE (self: Star) Write* (VAR R: Files.Rider);
  145.     BEGIN
  146.         Files.WriteNum(R, self.x);
  147.         Files.WriteNum(R, self.y)
  148.     END Write;
  149.     (* ---------------------------------- Constellation methods ---------------------------------- *)
  150.     PROCEDURE (self: Constellation) State* (): INTEGER;    (* unselected = 0; partially selected = 1; totally selected = 2 *)
  151.         VAR sum, i: INTEGER;
  152.     BEGIN sum := 0; i := 0;
  153.         WHILE i < self.nofpts DO
  154.             IF self.p[i].sel THEN INC(sum) END ;
  155.             INC(i)
  156.         END ;
  157.         IF sum = 0 THEN RETURN 0
  158.         ELSIF sum = self.nofpts THEN RETURN 2
  159.         ELSE RETURN 1
  160.         END
  161.     END State;
  162.     PROCEDURE (self: Constellation) Read* (VAR R: Files.Rider);
  163.         VAR ref, i: LONGINT;
  164.     BEGIN i := 0;
  165.         Files.ReadNum(R, ref); self.nofpts := SHORT(ref);
  166.         i := 0;
  167.         WHILE i < self.nofpts DO
  168.             Files.ReadNum(R, ref);
  169.             self.p[i] := GetStar(SHORT(ref));
  170.             INC(i)
  171.         END
  172.     END Read;
  173.     PROCEDURE (self: Constellation) Write* ( VAR R: Files.Rider);
  174.         VAR i: INTEGER;
  175.     BEGIN i := 0;
  176.         Files.WriteNum(R, self.nofpts);
  177.         WHILE i < self.nofpts DO Files.WriteNum(R, self.p[i].ref); INC(i) END
  178.     END Write;
  179.     (* ---------------------------------- Planet methods ---------------------------------- *)
  180.     PROCEDURE (self: Planet) Draw* (P: KeplerPorts.Port);
  181.     BEGIN
  182.         IF self.sel THEN
  183.             P.DrawRect(self.x - ptSize, self.y - ptSize, ptSize*2, ptSize*2, Display.white, Display.invert)
  184.         END
  185.     END Draw;
  186.     PROCEDURE (self: Planet) Calc*;
  187.     END Calc;
  188.     PROCEDURE (self: Planet) Read* (VAR R: Files.Rider);
  189.         VAR o: Object;
  190.     BEGIN self.Read^(R); ReadObj(R, o); self.c := o(Constellation)
  191.     END Read;
  192.     PROCEDURE (self: Planet) Write* (VAR R: Files.Rider);
  193.     BEGIN self.Write^(R); WriteObj(R, self.c)
  194.     END Write;
  195.     (* ---------------------------------- Graphic methods ---------------------------------- *)
  196.     PROCEDURE (G: Graph) Append*(o: Object);
  197.     BEGIN
  198.         IF o IS Star THEN
  199.             WITH o: Star DO
  200.                 IF G.stars = NIL THEN G.stars := o ELSE G.laststar.next := o END ;
  201.                 G.laststar := o; o.next := NIL
  202.             END
  203.         ELSE
  204.             WITH o: Constellation DO
  205.                 IF G.cons = NIL THEN G.cons := o ELSE G.lastcons.next := o END ;
  206.                 G.lastcons := o; o.next := NIL;
  207.                 G.notify(draw, G, o, NIL)
  208.             END
  209.         END
  210.     END Append;
  211.     PROCEDURE (G: Graph) FlipSelection*(p: Star);
  212.     BEGIN
  213.         IF p.sel THEN G.notify(draw, G, p, NIL); p.sel := FALSE
  214.         ELSE p.sel := TRUE; G.notify(draw, G, p, NIL); G.seltime := Oberon.Time()
  215.         END
  216.     END FlipSelection;
  217.     PROCEDURE DependsOn(c: Constellation; s: Star): BOOLEAN;
  218.         VAR i: INTEGER; p: Star;
  219.     BEGIN i := 0;
  220.         WHILE i < c.nofpts DO p := c.p[i];
  221.             IF p = s THEN RETURN TRUE
  222.             ELSIF (p IS Planet) & DependsOn(p(Planet).c, s) THEN RETURN TRUE
  223.             END ;
  224.             INC(i)
  225.         END ;
  226.         RETURN FALSE
  227.     END DependsOn;
  228.     PROCEDURE (G: Graph) Move*(s: Star; dx, dy: INTEGER);
  229.         VAR p: Star; c: Constellation;
  230.     BEGIN
  231.         KeplerPorts.InitBalloon(update);
  232.         c := G.cons;
  233.         WHILE c # NIL DO
  234.             IF DependsOn(c, s) THEN c.Draw(update) END ;
  235.             c := c.next
  236.         END ;
  237.         p := s^.next;
  238.         WHILE p # NIL DO
  239.             IF (p IS Planet) & DependsOn(p(Planet).c, s) THEN p.Draw(update) END ;
  240.             p := p.next
  241.         END ;
  242.         s.Draw(update); INC(s.x, dx); INC(s.y, dy); s.Draw(update);
  243.         p := s^.next;
  244.         WHILE p # NIL DO
  245.             IF (p IS Planet) & DependsOn(p(Planet).c, s) THEN p(Planet).Calc; p.Draw(update) END ;
  246.             p := p.next
  247.         END ;
  248.         c := G.cons;
  249.         WHILE c # NIL DO
  250.             IF DependsOn(c, s) THEN c.Draw(update) END ;
  251.             c := c.next
  252.         END ;
  253.         G.notify(restore, G, NIL, update)
  254.     END Move;
  255.     PROCEDURE (G: Graph) MoveSelection*(dx, dy: INTEGER);
  256.         VAR p: Star; c: Constellation;
  257.     BEGIN
  258.         KeplerPorts.InitBalloon(update);
  259.         p := G.stars;
  260.         WHILE p # NIL DO  (*expand selection*)
  261.             IF ~p.sel & (p IS Planet) & (p(Planet).c.State() > 0) THEN p.sel := TRUE END ;
  262.             p := p.next
  263.         END ;
  264.         c := G.cons;
  265.         WHILE c # NIL DO
  266.             IF c.State() # 0 THEN c.Draw(update) END ;
  267.             c := c.next
  268.         END ;
  269.         p := G.stars;
  270.         WHILE p # NIL DO
  271.             IF p.sel THEN
  272.                 p.Draw(update);
  273.                 IF p IS Planet THEN p(Planet).Calc
  274.                 ELSE INC(p.x, dx); INC(p.y, dy)
  275.                 END ;
  276.                 p.Draw(update)
  277.             END ;
  278.             p := p.next
  279.         END ;
  280.         c := G.cons;
  281.         WHILE c # NIL DO
  282.             IF c.State() # 0 THEN c.Draw(update) END ;
  283.             c := c.next
  284.         END ;
  285.         G.notify(restore, G, NIL, update)
  286.     END MoveSelection;
  287.     PROCEDURE ReverseStars(G: Graph);
  288.         VAR p, first, next: Star;
  289.     BEGIN p := G.stars;
  290.         G.laststar := p; first := NIL;
  291.         WHILE p # NIL DO
  292.             next := p.next; p.next := first;
  293.             first := p; p := next
  294.         END ;
  295.         G.stars := first
  296.     END ReverseStars;
  297.     PROCEDURE Release (self: Constellation);
  298.         VAR i: INTEGER; s: Star;
  299.     BEGIN i := 0;
  300.         WHILE i < self.nofpts DO s := self.p[i]; DEC(s.refcnt); INC(i) END
  301.     END Release;
  302.     PROCEDURE CutCons (G: Graph; prevc, c: Constellation);
  303.     BEGIN
  304.         IF prevc = NIL THEN G.cons := c.next ELSE prevc.next := c.next END ;
  305.         IF del.cons = NIL THEN del.cons := c ELSE del.lastcons.next := c END ;
  306.         del.lastcons := c;
  307.         IF G.lastcons = c THEN G.lastcons:= prevc END ;
  308.         Release(c); c.Draw(update)
  309.     END CutCons;
  310.     PROCEDURE CutStar (G:Graph; prevs, s: Star);
  311.     BEGIN
  312.         IF prevs = NIL THEN G.stars := s.next ELSE prevs.next := s.next END ;
  313.         IF del.stars = NIL THEN del.stars := s ELSE del.laststar.next := s END ;
  314.         del.laststar := s;
  315.         IF G.laststar = s THEN G.laststar := prevs END ;
  316.         IF s IS Planet THEN Release(s(Planet).c) END ;
  317.         s.ref := 0;
  318.         s.Draw(update)
  319.     END CutStar;
  320.     PROCEDURE DelStar(G: Graph; o: Object);
  321.         VAR s, prevs: Star;
  322.     BEGIN
  323.         s := G.stars; prevs := NIL;
  324.         WHILE (s # NIL) & (s # o) DO prevs := s; s := s.next END ;
  325.         IF s # NIL THEN CutStar(G, prevs, s) END
  326.     END DelStar;
  327.     PROCEDURE (G: Graph) Delete* (o: Object);
  328.         VAR c, prevc: Constellation; i: INTEGER;
  329.     BEGIN
  330.         KeplerPorts.InitBalloon(update);
  331.         delG := G; del.cons := NIL; del.stars := NIL;
  332.         IF o IS Constellation THEN
  333.             c := G.cons; prevc := NIL;
  334.             WHILE (c # NIL) & (c # o) DO prevc := c; c := c.next END ;
  335.             IF c # NIL THEN
  336.                 CutCons(G, prevc, c); i := 0;
  337.                 WHILE i < c.nofpts DO
  338.                     IF (c.p[i].refcnt = 0) & ~(c.p[i] IS Planet) THEN DelStar(G, c.p[i]) END ;
  339.                     INC(i)
  340.                 END
  341.             END
  342.         ELSE ASSERT(o(Star).refcnt = 0);
  343.             IF o IS Planet THEN
  344.                 c := o(Planet).c; Release(c); i := 0;
  345.                 WHILE i < c.nofpts DO
  346.                     IF (c.p[i].refcnt = 0) & ~(c.p[i] IS Planet) THEN DelStar(G, c.p[i]) END ;
  347.                     INC(i)
  348.                 END
  349.             END ;
  350.             DelStar(G, o)
  351.         END ;
  352.         IF del.cons # NIL THEN del.lastcons.next := NIL END ;
  353.         IF del.stars # NIL THEN del.laststar.next := NIL END ;
  354.         G.notify(restore, G, NIL, update)
  355.     END Delete;
  356.     PROCEDURE (G: Graph) DeleteSelection* (minstate: INTEGER);
  357.         VAR s, prevs: Star; c, prevc: Constellation;
  358.     BEGIN
  359.         delG := G; KeplerPorts.InitBalloon(update);
  360.     (*move all constellations with (State >= minstate) into del buffer*)
  361.         c := G.cons; prevc := NIL; del.cons := NIL;
  362.         WHILE c # NIL DO
  363.             IF c.State() >= minstate THEN CutCons(G, prevc, c) ELSE prevc := c END ;
  364.             c := c.next
  365.         END ;
  366.         IF del.cons # NIL THEN del.lastcons.next := NIL END ;
  367.     (*move all unused stars and planets with refcnt=0 & c.State>=minstate into del buffer*)
  368.         ReverseStars(G);
  369.         s := G.stars; prevs := NIL; del.stars := NIL;
  370.         WHILE s # NIL DO
  371.             IF (s.refcnt = 0) & (~(s IS Planet) OR s.sel OR (s(Planet).c.State() >= minstate)) THEN CutStar(G, prevs, s)
  372.             ELSE prevs := s
  373.             END ;
  374.             s := s.next
  375.         END ;
  376.         ReverseStars(G) ;
  377.         IF del.stars # NIL THEN del.laststar.next := NIL; ReverseStars(del) END ;
  378.         G.notify(restore, G, NIL, update)
  379.     END DeleteSelection;
  380.     PROCEDURE (G: Graph) All* (op: INTEGER);    (* deselect = 0; select = 1 *)
  381.         VAR p: Star;
  382.     BEGIN p := G.stars;
  383.         KeplerPorts.InitBalloon(update);
  384.         WHILE p # NIL DO
  385.             IF (op = 1) # p.sel THEN
  386.                 IF p.sel THEN p.Draw(update); p.sel := FALSE
  387.                 ELSE p.sel := TRUE; p.Draw(update); G.seltime := Oberon.Time()
  388.                 END
  389.             END ;
  390.             p := p.next
  391.         END ;
  392.         IF op = 0 THEN G.seltime := -1 END ;
  393.         G.notify(restore, G, NIL, update)
  394.     END All;
  395.     PROCEDURE Store(G: Graph; VAR R: Files.Rider; all: BOOLEAN);
  396.         VAR p, dummy: Star; c: Constellation;
  397.     BEGIN
  398.         p := G.stars;
  399.         NEW(dummy);
  400.         WHILE p # NIL DO
  401.             IF all OR (p.sel & ~(p IS Planet)) THEN
  402.                 WriteObj(R, p); p.ref := nofpt; INC(nofpt)
  403.             ELSIF p.sel & (p(Planet).c.State() = 2) THEN
  404.                 WriteObj(R, p); p.ref := nofpt; INC(nofpt)
  405.             ELSIF p.sel & (p(Planet).c.State() # 2) THEN
  406.                 dummy^ := p^; WriteObj(R, dummy); p.ref := nofpt; INC(nofpt)
  407.             END ;
  408.             p := p.next
  409.         END ;
  410.         c := G.cons;
  411.         WHILE c # NIL DO
  412.             IF all OR (c.State()=2) THEN WriteObj(R, c) END ;
  413.             c := c.next
  414.         END ;
  415.         Files.WriteNum(R, -1)
  416.     END Store;
  417.     PROCEDURE (G: Graph) Draw* (P: KeplerPorts.Port);
  418.         VAR s: Star; c: Constellation;
  419.     BEGIN
  420.         c := G.cons;
  421.         WHILE c # NIL DO c.Draw(P); c := c.next END ;
  422.         s := G.stars;
  423.         WHILE s # NIL DO s.Draw(P); s := s.next END
  424.     END Draw;
  425.     PROCEDURE (G: Graph) Write* (VAR R: Files.Rider);
  426.     BEGIN
  427.         Store(G, R, TRUE)
  428.     END Write;
  429.     PROCEDURE (G: Graph) WriteSel* (VAR R: Files.Rider);
  430.     BEGIN Store(G, R, FALSE)
  431.     END WriteSel;
  432.     PROCEDURE DoubleStarTab;
  433.         VAR h: StarTab; i: LONGINT;
  434.     BEGIN i := 0; NEW(h, LEN(starTab^)*2);
  435.         WHILE i < LEN(starTab^) DO h[i] := starTab[i]; INC(i) END ;
  436.         starTab := h
  437.     END DoubleStarTab;
  438.     PROCEDURE (G: Graph) Read* (VAR R: Files.Rider);
  439.         VAR o, o0: Object;
  440.     BEGIN loading := G;
  441.         G.stars := NIL; G.laststar := NIL; G.cons := NIL; G.lastcons := NIL; G.seltime := -1;
  442.         ReadObj(R, o0); o := o0;
  443.         WHILE o # NIL DO    (* append without notification *)
  444.             WITH o: Star DO
  445.                 IF G.stars = NIL THEN G.stars := o ELSE G.laststar.next := o END ;
  446.                 G.laststar := o; o.next := NIL;
  447.                 IF nofpt = LEN(starTab^) THEN DoubleStarTab END ;
  448.                 starTab[nofpt] := SYSTEM.VAL(LONGINT, o); INC(nofpt)
  449.             | o: Constellation DO 
  450.                 IF G.cons = NIL THEN G.cons := o ELSE G.lastcons.next := o END ;
  451.                 G.lastcons := o; o.next := NIL
  452.             END ;
  453.             ReadObj(R, o)
  454.         END
  455.     END Read;
  456.     PROCEDURE Old*(name: ARRAY OF CHAR): Graph;
  457.         VAR F: Files.File; R: Files.Rider; o: Object;
  458.     BEGIN F := Files.Old(name);
  459.         IF F # NIL THEN Files.Set(R, F, 0); Reset; ReadObj(R, o);
  460.             IF R.res = 0 THEN RETURN o(Graph) ELSE RETURN NIL END
  461.         ELSE RETURN NIL
  462.         END
  463.     END Old;
  464.     PROCEDURE *Dummy(op: INTEGER; g: Graph; c: Object; f: KeplerPorts.Port);
  465.     END Dummy;
  466.     PROCEDURE (G: Graph) CopySelection* (from: Graph; dx, dy: INTEGER);
  467.         VAR cpBuf: Files.File;
  468.             R: Files.Rider;
  469.             c, nextc: Constellation;
  470.             p, nextp: Star;
  471.             buf: Graph;
  472.     BEGIN
  473.         cpBuf := Files.New("");
  474.         Files.Set(R, cpBuf, 0);
  475.         Reset; from.WriteSel(R);
  476.         Files.Set(R, cpBuf, 0); Types.NewObj(buf, Types.TypeOf(from)); buf.notify := Dummy;
  477.         Reset; buf.Read(R);
  478.         p := buf.stars;
  479.         WHILE p # NIL DO nextp := p.next;
  480.             INC(p.x, dx); INC(p.y, dy);
  481.             IF (p.refcnt > 0) OR (p IS Planet) THEN G.Append(p) END;
  482.             p := nextp
  483.         END ;
  484.         c := buf.cons; KeplerPorts.InitBalloon(update);
  485.         WHILE c # NIL DO c.Draw(update); nextc := c.next;
  486.             IF G.cons = NIL THEN G.cons := c ELSE G.lastcons.next := c END ;
  487.             G.lastcons := c; c.next := NIL;
  488.             c := nextc
  489.         END ;
  490.         G.notify(restore, G, NIL, update)
  491.     END CopySelection;
  492.     PROCEDURE (G: Graph) SendToBack* (o: Object);
  493.         VAR i: INTEGER;
  494.             s: Star;
  495.             c: Constellation;
  496.     BEGIN
  497.         WITH
  498.             o: Star DO
  499.                 s := G.stars;
  500.                 IF o # s THEN
  501.                     WHILE s.next # o DO s := s.next END ;
  502.                     s.next := o.next; o.next := G.stars; G.stars := o;
  503.                     IF G.laststar = o THEN G.laststar := s END ;
  504.                     IF o IS Planet THEN    (* preserve topological order *)
  505.                         c := o(Planet).c;
  506.                         FOR i := 0 TO c.nofpts-1 DO
  507.                             G.SendToBack(c.p[i])
  508.                         END
  509.                     END
  510.                 END
  511.         | o: Constellation DO
  512.                 KeplerPorts.InitBalloon(update);
  513.                 c := G.cons;
  514.                 IF o # c THEN
  515.                     WHILE c.next # o DO c := c.next END ;
  516.                     c.next := o.next; o.next := G.cons; G.cons := o;
  517.                     IF G.lastcons = o THEN G.lastcons := c END ;
  518.                     o.Draw(update);
  519.                     G.notify(restore, G, NIL, update)
  520.                 END
  521.         END
  522.     END SendToBack;
  523.     PROCEDURE Unrelease(c: Constellation);
  524.         VAR i: INTEGER;
  525.     BEGIN i := 0;
  526.         WHILE i < c.nofpts DO INC(c.p[i].refcnt); INC(i) END
  527.     END Unrelease;
  528.     PROCEDURE Recall*;
  529.         VAR s, nexts: Star; c, nextc: Constellation;
  530.     BEGIN
  531.         IF delG # NIL THEN
  532.             s := del.stars;
  533.             WHILE s # NIL DO
  534.                 nexts := s.next; s.sel := FALSE; delG.Append(s);
  535.                 IF s IS Planet THEN Unrelease(s(Planet).c) END ;
  536.                 s := nexts
  537.             END ;
  538.             c := del.cons;
  539.             WHILE c # NIL DO nextc := c.next; delG.Append(c); Unrelease(c); c := nextc END ;
  540.             delG := NIL; del.cons := NIL; del.lastcons := NIL; del.stars := NIL; del.laststar := NIL
  541.         END
  542.     END Recall;
  543. BEGIN NEW(update); NEW(del); NEW(starTab, 1)
  544. END KeplerGraphs.
  545.